/********************************************************************************
* 
*	Project Name : S3C6410 Validation
*
*	Copyright 2008 by Samsung Electronics, Inc.
*	All rights reserved.
*
*	Project Description :
*		This software is only for verifying functions of the S3C6400.
*		Anybody can use this software without our permission.
*  
*--------------------------------------------------------------------------------
* 
*	File Name : AC97.c
*  
*	File Description :
*
*	Author	: Sung-Hyun, Na
*	Dept. : AP Development Team
*	Created Date : 2008/10/24
*	Version : 0.2
* 
*	History
*	- Version 0.1 (Y.H.Lee, 2007/03/09)
*	  -> Only available with STAC9767 AC97 Codec.
*   - Version 0.2 (Y.H.Lee, 2007/04/04)
*     -> Working with WM9713 AC97 Codec.
*
********************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "def.h"
#include "option.h"
#include "library.h"
#include "sfr6410.h"
#include "system.h"
#include "intc.h"
#include "gpio.h"
#include "dma.h"
#include "sysc.h"
#include "timer.h"

#include "ac97.h"
#include "audio.h"

#define AC97Inp32(offset) Inp32(AC97_BASE+offset)
#define AC97Inp16(offset) Inp16(AC97_BASE+offset)
#define AC97Outp32(offset, x) Outp32(AC97_BASE+offset, x)
#define AC97Outp16(offset, x) Outp16(AC97_BASE+offset, x)

static AC97_Infor 	g_oAC97Infor;

//////////
// Function Name : AC97_GetInfor
// Function Description : This function return Address of Global information Structure.
// Input : 	None
// Output :	AC97_Infor* - Addres of Global Information Structure.
// Version : v0.0
AC97_Infor* AC97_GetInfor(void)
{
	 return &(g_oAC97Infor);
}

//////////
// Function Name : AC97_Init
// Function Description : This function initilize Global information Structure.
// Input : 	None
// Output :	None
// Version : v0.0

u32 PCMBuf[AC97_REC_LEN];

void AC97_Init(void)
{
	AC97_Infor* pInfor;
	pInfor = AC97_GetInfor();
	{
		//DMA
		pInfor->m_uNumDma				= 	NUM_DMA1;
		pInfor->m_eDmaUnit				=	DMA1;
		pInfor->m_eAc97PCMInCh			=	DMA_A;
		pInfor->m_eAc97PCMOutCh		=	DMA_B;
		pInfor->m_eAc97MICInCh			=	DMA_C;		
		//Memory Buffer
        pInfor->m_pPCMInStartAddr		=	PCMBuf/*(u32 *)0x5100002c*/;
        pInfor->m_pPCMOutStartAddr		=	PCMBuf/*(u32 *)0x5100002c*/;
        pInfor->m_pMICInStartAddr		=	PCMBuf/*(u32 *)0x5100002c*/;
		pInfor->m_uPCMInSize			=	AC97_REC_LEN;
		pInfor->m_uPCMOutSize			=	AC97_REC_LEN;
		pInfor->m_uMICInSize				=	AC97_REC_LEN;			
		//Interupt Mode
		pInfor->m_uNumInt				= 	NUM_AC97;
		pInfor->m_ePCMOutIntMode		= 	PCMOUT_THRESHOLD_INT;
		pInfor->m_ePCMInIntMode			= 	PCMIN_THRESHOLD_INT;	
		pInfor->m_eMICInIntMode			= 	MICIN_THRESHOLD_INT;
		//Sampling Frequency
        pInfor->m_uSamplingRate			=	44100;
		//Codec Intormation
		pInfor->m_uCodecID				=	WM9713;
		pInfor->m_eADCSource			=	LINEIN;
        pInfor->m_uOutputVolume			=	0x10;
		//ISR Variable
		pInfor->m_usCodecReady			=	FALSE;
		pInfor->m_usAC97PCMInDone		=	FALSE;
		pInfor->m_usAC97MICInDone		=	FALSE;
		pInfor->m_usAC97PCMOutDone	=	FALSE;
		pInfor->m_usCmdHold				=	FALSE;
	}	
}

//////////
// Function Name : AC97_SetIntrDone
// Function Description : This function set Global indicator for isr.
// Input : 	eInt 	- Interrup Source
// 			usBool	- TRUE/FALSE
// Output :	None
// Version : v0.0
void AC97_SetIntrDone(AC97_INT eInt, u8 usBool)
{
	AC97_Infor* pInfor = AC97_GetInfor();
	if ( eInt == CODEC_READY_INT )
		pInfor->m_usCodecReady = usBool;
	else if ( eInt == PCMIN_OVERRUN_INT || eInt == PCMIN_THRESHOLD_INT)
		pInfor->m_usAC97PCMInDone = usBool;
	else if ( eInt == PCMOUT_UNDERRUN_INT ||eInt == PCMOUT_THRESHOLD_INT)
		pInfor->m_usAC97PCMOutDone = usBool;
	if ( eInt == MICIN_OVERRUN_INT || eInt == MICIN_THRESHOLD_INT)
		pInfor->m_usAC97MICInDone = usBool;
}

//////////
// Function Name : AC97_SetIntrDone
// Function Description : This function return Global indicator
// Input : 	eInt 	- Interrup Source
// Output :	u8
// Version : v0.0
u8 AC97_GetIntrDone(AC97_INT eInt)
{
	AC97_Infor* pInfor = AC97_GetInfor();
	if ( eInt == CODEC_READY_INT )
		return pInfor->m_usCodecReady;
	else if ( eInt == PCMIN_OVERRUN_INT || eInt == PCMIN_THRESHOLD_INT)
		return pInfor->m_usAC97PCMInDone;
	else if ( eInt == PCMOUT_UNDERRUN_INT ||eInt == PCMOUT_THRESHOLD_INT)
		return pInfor->m_usAC97PCMOutDone;
	else if ( eInt == MICIN_OVERRUN_INT || eInt == MICIN_THRESHOLD_INT)
		return pInfor->m_usAC97MICInDone;
	else
		return FALSE;
}

//////////
// Function Name : AC97_InitBuffer
// Function Description : This function set Memory Buffer
// Input : 	eCh 	- AC97 Interface Slot
// 			u32* 	- New Address
//			u32 	- New Data Size
// Output :	None
// Version : v0.0
void AC97_InitBuffer(AC97_CHANNEL eCh, u32* pAddr, u32 uDataSize)
{
	AC97_Infor* pInfor = AC97_GetInfor();
	if ( eCh == PCM_IN )
	{
		pInfor->m_pMemPcmIn = pAddr;
		pInfor->m_uPCMInBufferPointer = uDataSize;
	}
	else if ( eCh == PCM_OUT )
	{
		pInfor->m_pMemPcmOut = pAddr;
		pInfor->m_uPCMOutBufferPointer = uDataSize;
	}
	else if ( eCh == MIC_IN )
	{
		pInfor->m_pMemMicIn = pAddr;
		pInfor->m_uMICInBufferPointer = uDataSize;
	}
	else 
		Assert(0);	
}

//////////
// Function Name : AC97_PutDataMem
// Function Description : This function put data PCM Data Memory Buffer
// Input : 	AC97_CHANNEL - RX or TX
// 			u32 - PCM Data
// Output :	u32 - Buffer Pointer 
// Version : v0.0
s32 AC97_PutDataMem(AC97_CHANNEL eCh, u32 uData)
{
	AC97_Infor* pInfor = AC97_GetInfor();
	if ( eCh == PCM_OUT )
	{
		*(pInfor->m_pMemPcmOut++) = uData;
		pInfor->m_uPCMOutBufferPointer -= 4;
//		return pInfor->m_uPCMInBufferPointer; ??
        return pInfor->m_uPCMOutBufferPointer;
	}
	else if ( eCh == PCM_IN )
	{
		*(pInfor->m_pMemPcmIn++) = uData;
		pInfor->m_uPCMInBufferPointer -= 4;
		return pInfor->m_uPCMInBufferPointer;
	}
	else if ( eCh == MIC_IN )
	{
		*(pInfor->m_pMemMicIn++) =  uData;
		pInfor->m_uMICInBufferPointer -= 4;
		return pInfor->m_uMICInBufferPointer;
	}
	else
	{
		Assert(0);
		return FALSE;
	}	
}

//////////
// Function Name : AC97_PopDataMem
// Function Description : This function pop data PCM Data in the Memory Buffer
// Input : 	eCh - Interface Slot
// 			pData - return data address
// Output :	s32- buffer Cnt
// Version : v0.0
s32 AC97_PopDataMem(AC97_CHANNEL eCh, u32* pData)
{
	AC97_Infor* pInfor = AC97_GetInfor();
	if ( eCh == PCM_OUT )
	{
		*pData = *(pInfor->m_pMemPcmOut++);		
		pInfor->m_uPCMOutBufferPointer -= 4;	
		return pInfor->m_uPCMOutBufferPointer;
	}
	else if ( eCh == PCM_IN )
	{
		*pData = *(pInfor->m_pMemPcmIn++);
		pInfor->m_uPCMInBufferPointer -= 4;
		return pInfor->m_uPCMInBufferPointer;
	}
	else if ( eCh == MIC_IN )
	{
		*pData = *(pInfor->m_pMemMicIn++);
		pInfor->m_uMICInBufferPointer -= 4;
		return pInfor->m_uMICInBufferPointer;
	}
	else
	{
		Assert(0);
		return FALSE;
	}	
}

//////////
// Function Name : AC97_InitDMA
// Function Description : 
//   This function initialize DMA Controller for AC97 Controller.
// Input : 	eIFMode ->  Interface Channel
// Output : None
// Version : 0.0
void AC97_InitDMA(AC97_CHANNEL eIFMode)
{
	AC97_Infor* pInfor	 = AC97_GetInfor();
	DMA_CH		eDmaCh;
	DMAC*	pDmac;
	DMASELECT_eID eDmaId;
	DREQ_SRC eDmaReqSrc;
	u32 uDmaSrcAddr;
	u8 usDmaSrcFix;
	DREQ_SRC eDmaReqDst;
	u32 uDmaDstAddr;
	u8 usDmaDstFix;	
	u32 uTransferCnt;
	DATA_SIZE eTransferSize;		
	if ( eIFMode == PCM_OUT )
	{
		eDmaCh 		= pInfor->m_eAc97PCMOutCh;
		pDmac		= &(pInfor->m_oAc97PcmOutDma);
		eDmaId		= eSEL_AC_PCMOUT;		
		eDmaReqSrc	= MEM;				
		uDmaSrcAddr	= (u32) pInfor->m_pPCMOutStartAddr;
		usDmaSrcFix	= FALSE;		
		eDmaReqDst	= DMA1_AC_PCMout;
		uDmaDstAddr= AC97_BASE + rACPCMDATA;
		usDmaDstFix	= TRUE;			
		eTransferSize = WORD;
		uTransferCnt = pInfor->m_uPCMOutSize / 4;
	}
	else if ( eIFMode == PCM_IN )
	{
		eDmaCh 		= pInfor->m_eAc97PCMInCh;
		pDmac		= &(pInfor->m_oAc97PcmInDma);
		eDmaId		= eSEL_AC_PCMIN;		
		eDmaReqSrc	= DMA1_AC_PCMin;
		uDmaSrcAddr	= AC97_BASE + rACPCMDATA;
		usDmaSrcFix	= TRUE;		
		eDmaReqDst	= MEM;		
		uDmaDstAddr= (u32) pInfor->m_pPCMInStartAddr;
		usDmaDstFix	= FALSE;		
		uTransferCnt = pInfor->m_uPCMInSize / 4;
		eTransferSize = WORD;	
	}
	else if ( eIFMode == MIC_IN )
	{
		eDmaCh		= pInfor->m_eAc97MICInCh;
		pDmac		= &(pInfor->m_oAc97MicInDma);
		eDmaId		= eSEL_AC_MICIN;		
		eDmaReqSrc	= DMA1_AC_MICin;	
		uDmaSrcAddr	= AC97_BASE + rACMICDATA;
		usDmaSrcFix	= TRUE;		
		eDmaReqDst	= MEM;
		uDmaDstAddr= (u32) pInfor->m_pMICInStartAddr;
		usDmaDstFix	= FALSE;		
		uTransferCnt = pInfor->m_uMICInSize /4;
		eTransferSize = WORD;
	}
	INTC_Enable(pInfor->m_uNumDma);
	if ( pInfor->m_eDmaUnit == SDMA1)
		SYSC_SelectDMA(eDmaId, 0);
	else
		SYSC_SelectDMA(eDmaId, 1);
	DMAC_InitCh(pInfor->m_eDmaUnit , eDmaCh, pDmac);
	DMACH_Setup(eDmaCh, false, uDmaSrcAddr, usDmaSrcFix, uDmaDstAddr, usDmaDstFix, eTransferSize, uTransferCnt, DEMAND, eDmaReqSrc, eDmaReqDst, SINGLE, pDmac);
	DMACH_Start(pDmac);	
}



//////////
// Function Name : I2S_DMAStop
// Function Description : 
//   This function stops DMA channel for Ac97 Contorller
// Input : 	 ->  I2S Controller
//			eIFMode ->  Interface Channel
// Output : None
// Version : 0.0
// Example 
void AC97_DMAStop(AC97_CHANNEL eIFMode)
{
	AC97_Infor* pInfor	 = AC97_GetInfor();
	if ( eIFMode == PCM_OUT )	DMACH_Stop(&(pInfor->m_oAc97PcmOutDma));	
	else if ( eIFMode == PCM_IN )	DMACH_Stop(&(pInfor->m_oAc97PcmInDma));	
	else if ( eIFMode == MIC_IN ) 	DMACH_Stop(&(pInfor->m_oAc97MicInDma));		
}

//////////
// Function Name : I2S_DMAStop
// Function Description : 
//   This function stops DMA channel for Ac97 Contorller
// Input : 	 ->  I2S Controller
//			eIFMode ->  Interface Channel
// Output : None
// Version : 0.0
// Example 
void AC97_DMAIntrClr(AC97_CHANNEL eIFMode)
{
	AC97_Infor* pInfor	 = AC97_GetInfor();
	if ( eIFMode == PCM_OUT )
	{
		DMACH_ClearIntPending(&(pInfor->m_oAc97PcmOutDma));
		DMACH_ClearErrIntPending(&(pInfor->m_oAc97PcmOutDma));	
	}
	else if ( eIFMode == PCM_IN )
	{
		DMACH_ClearIntPending(&(pInfor->m_oAc97PcmInDma));
		DMACH_ClearErrIntPending(&(pInfor->m_oAc97PcmInDma));	
	}
	else if ( eIFMode == MIC_IN ) 
	{
		DMACH_ClearIntPending(&(pInfor->m_oAc97MicInDma));
		DMACH_ClearErrIntPending(&(pInfor->m_oAc97MicInDma));	
	}
}

//////////
// Function Name : PCM_SetDMAUnit
// Function Description : This function selec DMA for DMA Request of PCM Interface Contorller.
// Input : 	ePort - I2S Port Number 
//			eUnit - DMA Unit ID
// Output :	None
// Version : v0.0
void AC97_SetDMAUnit(DMA_UNIT eUnit)
{
	AC97_Infor* pInfor = AC97_GetInfor();
	if (eUnit == DMA1 )
	{	
		pInfor->m_uNumDma	= NUM_DMA1;					
		pInfor->m_eDmaUnit	= DMA1;						
	}
	else	 if (eUnit == SDMA1 )
	{
		pInfor->m_uNumDma	= NUM_SDMA1;		
		pInfor->m_eDmaUnit	= SDMA1;					
	}
	else 
		Assert('0');
}

//////////
// Function Name : AC97_SetIntrMode
// Function Description : This function set Interrupt Mode.
// Input : 	None
// Output :	u32 - Sample Rate
// Version : v0.0
void AC97_SetIntrMode(AC97_CHANNEL eCH, AC97_INT eIntMode)
{
	AC97_Infor* pInfor = AC97_GetInfor();	
	switch(eCH)
	{
		case PCM_OUT:
			pInfor->m_ePCMOutIntMode = eIntMode;
			break;
		case PCM_IN:
			pInfor->m_ePCMInIntMode = eIntMode;
			break;
		case MIC_IN:
			pInfor->m_eMICInIntMode = eIntMode;
			break;
	}	
}



//////////
// Function Name : AC97_SetPort
// Function Description : This function set GPIO Port for AC97 Controller.
// Input : 	ePort - AUDIO Port
// Output :	u8 - Sample Rate
// Version : v0.0
u8 AC97_SetPort(AUDIO_PORT ePort)
{
	if ( ePort == AUDIO_PORT0)
	{
		//Set GPD: AC97 Port
		#if 0
		GPIO_SetFunctionAll(eGPIO_D, 0x44444, 0); 
		GPIO_SetPullUpDownAll(eGPIO_D, 0x0);	
		#else
		GPIO_SetPullUpDownEach(eGPIO_D, eGPIO_1, 0x1);	// AC97BITCLK CDCLK Pull Down Enable	
		GPIO_SetFunctionEach(eGPIO_D, eGPIO_1, 0x4);		// AC97BITCLK
		GPIO_SetPullUpDownEach(eGPIO_D, eGPIO_0, 0x0);	// AC97nRESET Pull Up/Down Disable	
		GPIO_SetFunctionEach(eGPIO_D, eGPIO_0, 0x4);		// AC97nRESET
		GPIO_SetPullUpDownEach(eGPIO_D, eGPIO_2, 0x0);	// AC97SYNC Pull Up/Down Disable	
		GPIO_SetFunctionEach(eGPIO_D, eGPIO_2, 0x4);		// AC97SYNC
		GPIO_SetPullUpDownEach(eGPIO_D, eGPIO_3, 0x0);	// AC97SDIN Pull Up/Down Disable	
		GPIO_SetFunctionEach(eGPIO_D, eGPIO_3, 0x4);		// AC97SDIN
		GPIO_SetPullUpDownEach(eGPIO_D, eGPIO_4, 0x0);	// AC97SDOUT Pull Up/Down Disable	
		GPIO_SetFunctionEach(eGPIO_D, eGPIO_4, 0x4);		// AC97SDOUT
		#endif
	}					
	else if ( ePort == AUDIO_PORT1)
	{
		//Set GPE: AC97 Port
		#if 0
		GPIO_SetFunctionAll(eGPIO_E, 0x44444, 0); 
		GPIO_SetPullUpDownAll(eGPIO_E, 0x0);	
		#else
		GPIO_SetPullUpDownEach(eGPIO_E, eGPIO_1, 0x1);	// AC97BITCLK Pull Down Enable	
		GPIO_SetFunctionEach(eGPIO_E, eGPIO_1, 0x4);		// AC97BITCLK
		GPIO_SetPullUpDownEach(eGPIO_E, eGPIO_0, 0x0);	// I2S1 SCLK Pull Down Enable	
		GPIO_SetFunctionEach(eGPIO_E, eGPIO_0, 0x4);		// I2S1 SCLK
		GPIO_SetPullUpDownEach(eGPIO_E, eGPIO_2, 0x0);	// I2S1 LRCLK Pull Down Enable	
		GPIO_SetFunctionEach(eGPIO_E, eGPIO_2, 0x4);		// I2S1 LRCLk
		GPIO_SetPullUpDownEach(eGPIO_E, eGPIO_3, 0x0);	// I2S1 DIN Pull Down Enable	
		GPIO_SetFunctionEach(eGPIO_E, eGPIO_3, 0x4);		// I2S1 DIN
		GPIO_SetPullUpDownEach(eGPIO_E, eGPIO_4, 0x0);	// I2S1 DOUT Pull Down Enable	
		GPIO_SetFunctionEach(eGPIO_E, eGPIO_4, 0x4);		// I2S1 DOUT	
		#endif
	}
	else 
		return FALSE;
	Delay(1000);	
	return TRUE;
}

//////////
// Function Name : AC97_ClosePort
// Function Description : This function set GPIO Port Input of the AC97 Controller.
// Input : 	ePort - AUDIO Port
// Output :	u8 - Sample Rate
// Version : v0.0
u8 AC97_ClosePort(AUDIO_PORT ePort)
{
	switch(ePort)
	{
		case AUDIO_PORT0 :
			GPIO_SetFunctionAll(eGPIO_D, 0x0, 0x0);
			break;
		case AUDIO_PORT1 :
			GPIO_SetFunctionAll(eGPIO_E, 0x0, 0x0);
			break;
		default :
			return FALSE;
	}
	Delay(1000);	
	return TRUE;
}

/*---------------------------------- APIs of rGLBCTRL ---------------------------------*/

//////////
// Function Name : AC97_InitACLINK
// Function Description : 
//   This function cold reset AC97 Codec and activates AC Link.
// Input : 	None
// Output : TRUE - Activattion 
// Version : v0.1
u8 AC97_InitACLINK(void)
{
	u32 uCnt=0;
	UART_Printf("\nAC97 Initialization...\n");	       
    	//Codec Ready Check using Codec Ready Interrupt
   	AC97_ColdReset();			 //Cold Reset 
	AC97_SetIntrDone(CODEC_READY_INT, FALSE);
	AC97_IntrCon(CODEC_READY_INT, ENABLE);
	INTC_SetVectAddr(NUM_AC97, ISR_AC97);	
	INTC_Enable(NUM_AC97);
	while(!AC97_GetIntrDone(CODEC_READY_INT))
	{
	 	UART_Printf(".");
		Delay(3000);
      	uCnt++;         	
       	if(uCnt==20)
			break;
	}	
	UART_Printf("\n");
	if(uCnt>=20)
	{
		UART_Printf("\nAC Link is not Activated.");
		UART_Printf("\nCheck on connection between AP and AC97 CODEC.\n");
		UART_Printf("\nBye. ");		
		return false;
	}
	else
	{
		return true;
	}
}



//////////
// Function Name : AC97_WarmReset
// Function Description : 
//   This function warm reset AC97 Codec.
// Input : 	None
// Output : None
// Version : v0.1
void AC97_WarmReset(void)
{
	u32 uGlobalCon;
	
	UART_Printf("\n=>Warm Reset\n");
	AC97_CodecCmd(READ,0x26,0x0); 						//To avoid issuing unwanted command to Codec after warm reset 

	uGlobalCon = Inp32(AC97_BASE+rACGLBCTRL) & ~(0xf);		//except Transfer Data, AC-Link On, Warm Reset and cold Reset bits

	uGlobalCon |= AC97_Enable_Warm_Reset;					//Wakeup Reset  Bit Set
	AC97Outp32(rACGLBCTRL, uGlobalCon);
	Delay(1000);												//wait 1us for warm reset
	AC97_ControllerState();
	
	uGlobalCon &= ~AC97_Enable_Warm_Reset;					//Wakeup Reset Bit Clear
	AC97Outp32(rACGLBCTRL, uGlobalCon);
	AC97_ControllerState();
	Delay(AC97_DebugDelay);

	uGlobalCon |= AC97_Enable_ACLINK;						//AC - Link On	
	AC97Outp32(rACGLBCTRL, uGlobalCon);
	AC97_ControllerState();
	Delay(AC97_DebugDelay);
	
	uGlobalCon |= AC97_Enable_Transfer_ACLINK;				//Data Transfer Enable
	AC97Outp32(rACGLBCTRL, uGlobalCon);
	Delay(AC97_DebugDelay);
	AC97_ControllerState();
	
	//AC97_CodecCmd(WRITE,0x00,0x683F);		
	UART_Printf("AC97 Codec Powerdown Ctrl/Stat Reg. Value (at 0x26): 0x%x\n", AC97_CodecCmd(READ,0x26,0x0000));	
}

//////////
// Function Name : AC97_ColdReset
// Function Description : 
//   This function cold reset AC97 Codec.
// Input : 	None
// Output : None
// Version : v0.1
void AC97_ColdReset(void)
{
	u32 uGlobalCon;		
	UART_Printf("\n=>Cold Reset\n");
	//uGlobalCon = Inp32(AC97_BASE+rACGLBCTRL);
	uGlobalCon = AC97_Enable_Cold_Reset;			//Cold Reset : Assert RESET# Pin
	AC97Outp32(rACGLBCTRL, uGlobalCon);
	Delay(AC97_DebugDelay);	
	AC97_ControllerState();	
	uGlobalCon &= ~AC97_Enable_Cold_Reset;		//Cold Reset : De-Assert RESET# Pin
	AC97Outp32(rACGLBCTRL, uGlobalCon);
	Delay(AC97_DebugDelay);
	AC97_ControllerState();	
	
	AC97_WarmReset();						//for WM9713 Codec 
	
	AC97_ControllerState();	
	uGlobalCon |= (1<<2);
	AC97Outp32(rACGLBCTRL, uGlobalCon);
	AC97_ControllerState();
	Delay(AC97_DebugDelay);	
	uGlobalCon |= (1<<3);
	AC97Outp32(rACGLBCTRL, uGlobalCon);
	AC97_ControllerState();	
	//UART_Printf("AC97 Codec Powerdown Ctrl/Stat Reg. Value (at 0x26): 0x%x\n", AC97_CodecCmd(READ,0x26,0x0000));	
}

//////////
// Function Name : AC97_ShuntOffAcLink
// Function Description : 
//   This function clrear Interrupt Pending Bits of AC97 Controller.
// Input : 	None
// Output : None
// Version : v0.1
void AC97_ShuntOffAcLink(void)
{
	u32 uGlobalCon;
	if (AC97_ControllerState() == State_Active)
	{
		uGlobalCon= AC97Inp32(rACGLBCTRL);
	 	AC97Outp32(rACGLBCTRL, uGlobalCon & ~(1<<2));				//Hold AC-Link Data
	 	AC97Outp32(rACGLBCTRL, uGlobalCon & ~((1<<2)|(1<<3)));	//Don't Hold AC -Link Data
	}
}
//////////
// Function Name : AC97_IntrClr
// Function Description : 
//   This function clrear Interrupt Pending Bits of AC97 Controller.
// Input : 	eIntStatus	- Interrupt Condition
// Output : None
// Version : v0.1
void AC97_SetTransferCh(AC97_CHANNEL eCh, AC97_TRANSFER_MODE eTransferMode)
{
	u32 uEnTransferCh;
    
   	uEnTransferCh= AC97Inp32(rACGLBCTRL);
	uEnTransferCh = uEnTransferCh & ~(0x3 << (u32) eCh) | ( (u32) eTransferMode << (u32) eCh );
	uEnTransferCh |= (3<<2); 		
	AC97Outp32(rACGLBCTRL, uEnTransferCh); 
	Delay(10);		
}

//////////
// Function Name : AC97_IntrClr
// Function Description : 
//   This function clrear Interrupt Pending Bits of AC97 Controller.
// Input : 	eIntStatus	- Interrupt Condition
// Output : None
// Version : v0.1
void AC97_IntrClr(AC97_INT eIntStatus)
{
	u32 urGLBSTRL = Inp32(AC97_BASE+rACGLBCTRL);
	urGLBSTRL |= ((u32) eIntStatus) << 24;
	Outp32(AC97_BASE+rACGLBCTRL, urGLBSTRL);
}

//////////
// Function Name : AC97_IntrCon
// Function Description : 
//   This function clrear Interrupt Pending Bits of AC97 Controller.
// Input : 	eIntStatus	- Interrupt Condition
// Output : None
// Version : v0.1
void AC97_IntrCon(AC97_INT eInt, u8 usBool)
{
	u32 uInt;
	uInt = AC97Inp32(rACGLBCTRL);
	if ( usBool )
		uInt |= (eInt << 16);
	else
		uInt &= ~(eInt << 16);	
	AC97Outp32(rACGLBCTRL, uInt);
}



//////////
// Function Name : AC97_ClearInt
// Function Description : 
//   This function write Codec Register Value to Codec using Slot1, Slot2 on AC-Link or Read Codec Register Value.
// Input : 	eCmd	- Write/Read
//			uCmdOffset	- Codec Register Offset
//			uCmdData	- Codec Register Value or None
// Output : u16 - Codec Register Value or Zero
// Version : v0.1
void AC97_ClearInt(AC97_INT eInt)
{
	u32 urGLBSTRL = Inp32(AC97_BASE+rACGLBCTRL);
	urGLBSTRL |= ((u32) eInt) << 24;
	AC97Outp32(rACGLBCTRL, urGLBSTRL);	
}


/*---------------------------------- APIs of rGLBSTAT ---------------------------------*/
//////////
// Function Name : AC97_CodecCmd
// Function Description : 
//   This function write Codec Register Value to Codec using Slot1, Slot2 on AC-Link or Read Codec Register Value.
// Input : 	eCmd	- Write/Read
//			uCmdOffset	- Codec Register Offset
//			uCmdData	- Codec Register Value or None
// Output : u16 - Codec Register Value or Zero
// Version : v0.1
AC97_State AC97_ControllerState(void)
{
	u32 uState;
	uState= Inp32(AC97_BASE+rACGLBSTAT);
	if((uState & 0x7) == 0)
		UART_Printf("AC97 Controller State: Idle\n"); 
	else if ((uState & 0x7) == 1)
		UART_Printf("AC97 Controller State: Init\n"); 
	else if ((uState & 0x7) == 2)
		UART_Printf("AC97 Controller State: Ready\n"); 
	else if ((uState & 0x7) == 3)	
		UART_Printf("AC97 Controller State: Active\n"); 
	else if ((uState & 0x7) == 4)	
		UART_Printf("AC97 Controller State: LP\n"); 
	else if ((uState & 0x7) == 5)	
		UART_Printf("AC97 Controller State: Warm\n"); 
	return (AC97_State)uState;
}


//////////
// Function Name : AC97_InterruptState
// Function Description : 
//   This function return Codec Interrupt Statuse.
// Input : 	None
// Output : u32 - Codec Interrupt status
// Version : v0.1
u32 AC97_InterruptState(void)
{
	u32 uState = AC97Inp32(rACGLBSTAT);
	uState = (uState >> 16) & 0x7f;
	if ( uState & CODEC_READY_INT )
		UART_Printf("AC97 Interrupt State: Codec Ready\n"); 
	if ( uState & PCMOUT_UNDERRUN_INT)
		UART_Printf("AC97 Interrupt State: PCM Out FIFO Underrun\n"); 
	if ( uState & PCMIN_OVERRUN_INT)
		UART_Printf("AC97 Interrupt State: PCM In FIFO Overrun\n"); 
	if ( uState & MICIN_OVERRUN_INT)
		UART_Printf("AC97 Interrupt State: MIC In FIFO Overrun\n"); 
	//if ( uState & PCMOUT_THRESHOLD_INT)
	//	UART_Printf("AC97 Interrupt State: PCM Out FIFO Half Empty\n"); 
	//if ( uState & PCMIN_THRESHOLD_INT)
	//	UART_Printf("AC97 Interrupt State: PCM  In FIFO Half Full\n"); 
	//if ( uState & MICIN_THRESHOLD_INT)
	//	UART_Printf("AC97 Interrupt State: MIC In FIFO Half Full\n"); 
	return uState;	
}


/*---------------------------------- APIs of rCODEC_CMD and rCODEC_STAT ---------------------------------*/
//////////
// Function Name : AC97_CodecCmd
// Function Description : 
//   This function write Codec Register Value to Codec using Slot1, Slot2 on AC-Link or Read Codec Register Value.
// Input : 	eCmd	- Write/Read
//			uCmdOffset	- Codec Register Offset
//			uCmdData	- Codec Register Value or None
// Output : u16 - Codec Register Value or Zero
// Version : v0.1
u16 AC97_CodecCmd(AC97_CMD eCmd, u8 uCmdOffset, u16 uCmdData)
{
	//u32 uState;
	u16 uCodecStat, uCodecRegister;

	if(eCmd == WRITE)
	{
		AC97Outp32(rACCODECCMD, (0<<23) |(uCmdOffset << 16) | (uCmdData << 0));
		Delay(AC97_CMDWriteDelay);														//Delay more than 1/48Khz(20.83us)
		return 0;
	}
	else if (eCmd == READ) 
	{
		AC97Outp32(rACCODECCMD, (1<<23) |(uCmdOffset << 16) |(0 << 0));
		Delay(AC97_CMDReadDelay);	
		AC97_CodecStatRegister(&uCodecStat, &uCodecRegister);
		//Delay more than 1/48Khz(20.83us)
		#if 0
		while(1)
		{	
			uState = AC97Inp32(rACCODECSTAT);
			if (((uState & 0x7f0000) >> 16) == uCmdOffset);
				break;		
		}
		#endif		
		return uCodecRegister;
	}
	else
		return 0;
}

//////////
// Function Name : AC97_CodecCmd
// Function Description : 
//   This function write Codec Register Value to Codec using Slot1, Slot2 on AC-Link or Read Codec Register Value.
// Input : 	eCmd	- Write/Read
//			uCmdOffset	- Codec Register Offset
//			uCmdData	- Codec Register Value or None
// Output : u16 - Codec Register Value or Zero
// Version : v0.1
void AC97_CodecCmdManually(void)
{
	AC97_CMD	eCmd;
	u16	uCmdData;
	u8	uCmdOffset;
	u32 uTemp;	
	//AC97_SetCmdHold(TRUE);
	UART_Printf("\n0. Write	1. Read\n");
	uTemp = UART_GetIntNum();
	if (uTemp == 0)
		eCmd = WRITE;
	else 
		eCmd = READ;	
	UART_Printf("\nInput Codec Register(HEXA : 0x....)\n");
	uCmdOffset = UART_GetIntNum();	
	UART_Printf("\nInput Cmd(HEXA : 0x....)\n");
	uCmdData = UART_GetIntNum();
	uTemp = AC97_CodecCmd(eCmd, uCmdOffset, uCmdData);
	if (eCmd == READ)
		UART_Printf("Read Register : 0x%x,	Value : 0x%x\n",uCmdOffset,uTemp);
	else
		UART_Printf("Write Register : 0x%x,	Value : 0x%x\n",uCmdOffset,AC97_CodecCmd(READ, uCmdOffset, 0x0000));
	//AC97_SetCmdHold(FALSE);
}

//////////
// Function Name : AC97_CodecCmdNoDelay
// Function Description : 
//   This function write or Read CMD without delay. 
//   This function may be caused wrong operation. only using to calculate dalay for right Codec CMD Operation.
// Input : 	eCmd	- Write/Read
//			uCmdOffset	- Codec Register Offset
//			uCmdData	- Codec Register Value or None
// Output : None
// Version : v0.1
void AC97_CodecCmdNoDelay(AC97_CMD eCmd, u8 uCmdOffset, u16 uCmdData)
{
	AC97Outp32(rACCODECCMD, (eCmd << 23) |(uCmdOffset << 16) | (uCmdData << 0));	
}

//////////
// Function Name : AC97_CodecStatRegister
// Function Description : 
//   This function Read Codec Status Register
// Input : 	*uAddress	- Address of Codec Status Register to returne
//			*uData	- Register Value to return
// Output : None
// Version : v0.1
void AC97_CodecStatRegister(u16* uAddress, u16* uData)
{
	u32 uCodecStat = AC97Inp32(rACCODECSTAT);
	*uAddress = (uCodecStat & (0x7f << 16)) >> 16;
	*uData = (uCodecStat & (0xffff));
}

/*---------------------------------- APIs of rPCMADDR & rMICADDR---------------------------*/
//////////
// Function Name : AC97_GetFifoAddr
// Function Description : 
//   This function gets Fifo Address
// Input : 	eCh		- AC97 Interface
// Output : u32		- Fifo Address(0x0 ~ 0xf)
// Version : v0.1
u32 AC97_GetFifoAddr(AC97_CHANNEL eCh)
{
	u32 uPCMAddr = Inp32(AC97_BASE+rACPCMADDR);
	u32 uMICAddr = Inp32(AC97_BASE+rACMICADDR); 
	if ( eCh == PCM_OUT )
	{
		return ((AC97Inp32(rACPCMADDR) >> 24) & 0xf);
	}
	else if ( eCh == PCM_IN )		
	{
		return ((AC97Inp32(rACPCMADDR) >> 16) & 0xf);
	}
	else if ( eCh == MIC_IN )
	{
		return ((AC97Inp32(rACMICADDR) >> 24) & 0xf);
	}
	else 
		return FALSE;

}

//////////
// Function Name : AC97_SetFifoAddr
// Function Description : 
//   This function Sets Fifo Address
// Input : 	eCh		- AC97 Interface
//			uAddr	- Fifo Address
// Output : none
// Version : v0.1
void AC97_SetFifoAddr(AC97_CHANNEL eCh, u8 uAddr)
{
	u32 uPCMAddr = Inp32(AC97_BASE+rACPCMADDR);
	u32 uMICAddr = Inp32(AC97_BASE+rACMICADDR); 
	if ( eCh == PCM_OUT )
	{
		uPCMAddr &= ~((0xf) << 16) | (uAddr << 16);
	}
	else if ( eCh == PCM_IN )		
	{
		uPCMAddr &= ~((0xf) << 0) | (uAddr << 0);
	}
	else if ( eCh == MIC_IN )
	{
		uMICAddr &= ~((0xf) << 0) | (uAddr << 0);
	}

}
/*---------------------------- APIs of rPCMDATA & rACMICDATA-------------------------*/
//////////
// Function Name : AC97_SetDataFifo
// Function Description : 
//   This function puts data into PCMIn Fifo.
// Input : 	u32			- 32bit Data
// Output : NONE
// Version : v0.1
void AC97_SetDataFifo(u32 uPCMData)
{
	Outp32(AC97_BASE+rACPCMDATA, uPCMData);		
}

//////////
// Function Name : AC97_GetDataFifo
// Function Description : 
//   This function gets data from PCMIn or MICIn Fifo.
// Input : 	eCh			- 32bit Data
// Output : NONE
// Version : v0.1
u32 AC97_GetDataFifo(AC97_CHANNEL eCh)
{
	if ( eCh == PCM_IN)
		return AC97Inp32(rACPCMDATA);
	else if (eCh == MIC_IN)
		return AC97Inp32(rACMICDATA);
	else 
		return FALSE;
}
/*---------------------------------- APIs of ISR for AC97 ---------------------------------*/
//////////
// Function Name : ISR_AC97
// Function Description : 
//   This function is ISR for AC97 Controller.
// Input : 	None
// Output : NONE
// Version : v0.1
void __irq ISR_AC97(void)
{
	u32 uState;
	AC97_Infor* pInfor = AC97_GetInfor();
	INTC_Disable(NUM_AC97);
	uState = AC97_InterruptState();
	if ( uState & CODEC_READY_INT )
		Isr_AC97CodecReady();	
	if ( uState & PCMOUT_UNDERRUN_INT )
		Isr_AC97PCMOUT_UNDERRUN_INT();	
	if ( uState & PCMIN_OVERRUN_INT )
		Isr_AC97PCMIN_OVERRUN_INT();	
	if ( uState & MICIN_OVERRUN_INT )
		Isr_AC97MICIN_OVERRUN_INT();
	if ( uState & PCMOUT_THRESHOLD_INT )
		Isr_AC97PCMOUT_THRESHOLD_INT();
	if ( uState & PCMIN_THRESHOLD_INT )
		Isr_AC97PCMIN_THRESHOLD_INT();
	if ( uState & MICIN_THRESHOLD_INT )
		Isr_AC97MICIN_THRESHOLD_INT();				

}

//////////
// Function Name : Isr_AC97CodecReady
// Function Description : 
//   This function is ISR for Codec Ready interrupt
// Input : 	None
// Output : NONE
// Version : v0.1
void Isr_AC97CodecReady(void)
{ 
	AC97_SetIntrDone(CODEC_READY_INT, TRUE);
	UART_Printf("Codec Ready!\n");	
	AC97_ClearInt(CODEC_READY_INT);
	AC97_IntrCon(CODEC_READY_INT, DISABLE);
	INTC_ClearVectAddr();
}

//////////
// Function Name : Isr_AC97PCMOUT_UNDERRUN_INT
// Function Description : 
//   This function is ISR for PCM Out FIFO Underrun Interrupt.
// Input : 	None
// Output : NONE
// Version : v0.1
void Isr_AC97PCMOUT_UNDERRUN_INT(void)
{

}

//////////
// Function Name : Isr_AC97PCMIN_OVERRUN_INT
// Function Description : 
//   This function is ISR for PCM In FIFO Overrun Interrupt.
// Input : 	None
// Output : NONE
// Version : v0.1
void Isr_AC97PCMIN_OVERRUN_INT(void)
{
}

//////////
// Function Name : Isr_AC97MICIN_OVERRUN_INT
// Function Description : 
//   This function is ISR for MIC In FIFO Overrun Interrupt.
// Input : 	None
// Output : NONE
// Version : v0.1
void Isr_AC97MICIN_OVERRUN_INT(void)
{
}

//////////
// Function Name : Isr_AC97PCMOUT_THRESHOLD_INT
// Function Description : 
//   This function is ISR for PCM Out FIFO Threshold Interrupt.
//		- This ISR move data from PCM Out Memory Buffer to PCM Out FIFO.
// Input : 	None
// Output : NONE
// Version : v0.1
void Isr_AC97PCMOUT_THRESHOLD_INT(void)
{
	u32 uCnt;
	u32 uData = 0;
	AC97_Infor* pInfor = AC97_GetInfor();	

	INTC_Disable(NUM_AC97);
	AC97_IntrCon(PCMOUT_THRESHOLD_INT, DISABLE);		
	for(uCnt = 0; uCnt < PCM_OUT_TRIGGER; uCnt++)
	{	
		if(AC97_PopDataMem(PCM_OUT, &uData) <= 0)  			
			break;		
		AC97_SetDataFifo(uData);
	}		
	AC97_ClearInt(PCMOUT_THRESHOLD_INT);
	INTC_ClearVectAddr();	
	if(pInfor->m_uPCMOutBufferPointer <= 0) 
	{
		AC97_SetIntrDone(PCMOUT_THRESHOLD_INT, TRUE);
	}
	else
	{
		AC97_IntrCon(PCMOUT_THRESHOLD_INT, ENABLE);
		INTC_Enable(NUM_AC97);
	}
}

//////////
// Function Name : Isr_AC97PCMIN_THRESHOLD_INT
// Function Description : 
//   This function is ISR for PCM In FIFO Threshold Interrupt.
//		- This ISR move data from PCM in FIFO to PCM In Memory Buffer.
// Input : 	None
// Output : NONE
// Version : v0.1
void Isr_AC97PCMIN_THRESHOLD_INT(void)
{
	u32 uCnt; 
	AC97_Infor* pInfor = AC97_GetInfor();	
	INTC_Disable(NUM_AC97);
	AC97_IntrCon(PCMIN_THRESHOLD_INT, DISABLE);	
	for(uCnt=0; uCnt < PCM_IN_TRIGGER; uCnt++)
	{
		if ( AC97_PutDataMem(PCM_IN, AC97_GetDataFifo(PCM_IN)) <= 0)
			break;	
	}			
	INTC_ClearVectAddr();
	AC97_ClearInt(PCMIN_THRESHOLD_INT);
	if(pInfor->m_uPCMInBufferPointer <= 0) 
	{
		AC97_SetIntrDone(PCMIN_THRESHOLD_INT, TRUE);	
	}
	else
	{	
		AC97_IntrCon(PCMIN_THRESHOLD_INT, ENABLE);
		INTC_Enable(NUM_AC97);
	}	
}

//////////
// Function Name : Isr_AC97MICIN_THRESHOLD_INT
// Function Description : 
//   This function is ISR for MIC In FIFO Threshold Interrupt.
//		- This ISR move data from MIC in FIFO to MIC in Memory Buffer.
// Input : 	None
// Output : NONE
// Version : v0.1
void Isr_AC97MICIN_THRESHOLD_INT(void)
{
	u32 uCnt; 
	AC97_Infor* pInfor = AC97_GetInfor();	
	INTC_Disable(NUM_AC97);
	AC97_IntrCon(MICIN_THRESHOLD_INT, DISABLE);	
	for(uCnt=0; uCnt < MIC_IN_TRIGGER; uCnt++)
	{
		if ( AC97_PutDataMem(MIC_IN, AC97_GetDataFifo(MIC_IN)) <= 0)
			break;	
	}			
	INTC_ClearVectAddr();
	AC97_ClearInt(MICIN_THRESHOLD_INT);
	if(pInfor->m_uMICInBufferPointer <= 0) 
	{
		AC97_SetIntrDone(MICIN_THRESHOLD_INT, TRUE);	
	}
	else
	{	
		AC97_IntrCon(MICIN_THRESHOLD_INT, ENABLE);
		INTC_Enable(NUM_AC97);
	}	
}

/*---------------------------------- APIs of ISR for DMA by AC97 Request ---------------------------------*/
//////////
// Function Name : Isr_AC97DmaRestart
// Function Description : 
//   This function is ISR for DMA Request of AC97 Controller
//		- This ISR restart DMA.
// Input : 	None
// Output : NONE
// Version : v0.1
void __irq Isr_AC97DmaRestart(void)
{
	AC97_Infor* pInfor = AC97_GetInfor();
	DMA_CH eReqCh = DMACH_GetChannelNumber(&(pInfor->m_oAc97PcmInDma));
	INTC_Disable(pInfor->m_uNumDma);
	if ( eReqCh & pInfor->m_eAc97PCMInCh)
		AC97_DMARestart(PCM_IN);	
	if ( eReqCh & pInfor->m_eAc97PCMOutCh)
		AC97_DMARestart(PCM_OUT);
	if ( eReqCh & pInfor->m_eAc97MICInCh)
		AC97_DMARestart(MIC_IN);
	INTC_ClearVectAddr();
}

//////////
// Function Name : Isr_AC97DmaDone
// Function Description : 
//   This function is ISR for DMA Request of AC97 Controller
//		- This ISR stop DMA.
// Input : 	None
// Output : NONE
// Version : v0.1
void __irq Isr_AC97DmaDone(void)
{
	AC97_Infor* pInfor = AC97_GetInfor();
	DMA_CH eReqCh = DMACH_GetChannelNumber(&(pInfor->m_oAc97PcmInDma));
	INTC_Disable(pInfor->m_uNumDma);
	if ( eReqCh & pInfor->m_eAc97PCMInCh)
		AC97_DMADone(PCM_IN);	
	if ( eReqCh & pInfor->m_eAc97PCMOutCh)
		AC97_DMADone(PCM_OUT);
	if ( eReqCh & pInfor->m_eAc97MICInCh)
		AC97_DMADone(MIC_IN);
	INTC_ClearVectAddr();
}

//////////
// Function Name : AC97_DMADone
// Function Description : 
//   This function stop DMA Transfer.
//		- This ISR restart DMA.
// Input : 	eCh - AC97 channel
// Output : NONE
// Version : v0.1
void AC97_DMADone(AC97_CHANNEL eCh)
{
	AC97_Infor* pInfor = AC97_GetInfor();
	INTC_Disable(pInfor->m_uNumDma);
	AC97_DMAIntrClr(eCh);	
	AC97_SetIntrDone((AC97_INT)(1 << ((u32)eCh/2 - 1)), TRUE);
	if ( eCh == PCM_IN )
		UART_Printf("\nAC97 PCM In Slot DMA Transfer Done.\n");		
	else if ( eCh == PCM_OUT )
		UART_Printf("\nAC97 PCM Out Slot DMA Transfer Done.\n");		
	else if ( eCh == MIC_IN )
		UART_Printf("\nAC97 MIC In Slot DMA Transfer Done.\n");	
	INTC_ClearVectAddr();
}

//////////
// Function Name : Isr_AC97DmaRestart
// Function Description : 
//   This function restart DMA transfer channel
// Input : 	eCh - AC97 channel
// Output : NONE
// Version : v0.1
void AC97_DMARestart(AC97_CHANNEL eCh)
{
	AC97_Infor* pInfor = AC97_GetInfor();
	INTC_Disable(pInfor->m_uNumDma);
	AC97_SetTransferCh(eCh, OFF);
	AC97_DMAIntrClr(eCh);	
	AC97_InitDMA(eCh);
	if ( eCh == PCM_IN )
		UART_Printf("\nAC97 PCM In Slot DMA Transfer Restart.\n");		
	else if ( eCh == PCM_OUT )
		UART_Printf("\nAC97 PCM Out Slot DMA Transfer Restart.\n");		
	else if ( eCh == MIC_IN )
		UART_Printf("\nAC97 MIC In Slot DMA Transfer Restart.\n");		
	AC97_SetTransferCh(eCh, DMA);	
	INTC_ClearVectAddr();	
}

/*---------------------------------- APIs of AC97 Codec ---------------------------------*/
//////////
// Function Name : AC97_SetOutputVolume
// Function Description : 
//   This function command Codec to increase or decrease Gain of DAC.
//		- This ISR stop DMA.
// Input : 	uUpDownVolume - Direction of Gain Increasing(Up/Down)
// Output : NONE
// Version : v0.1
u8 AC97_SetOutputVolume(u8 uUpDownVolume)
{
	AC97_Infor* pInfor = AC97_GetInfor();
	
	switch(pInfor->m_uCodecID)
	{
		case WM9713:
			if( ( uUpDownVolume == 'u') || (uUpDownVolume == 'U') )
				(pInfor->m_uOutputVolume)--;
			else if ( ( uUpDownVolume == 'd') || (uUpDownVolume == 'D') ) 
				(pInfor->m_uOutputVolume)++;
			if (WM9713_SetVolume(AUDIO_Tx, pInfor->m_uOutputVolume))
			{
				UART_Printf("\nSet Level : 0x%x", pInfor->m_uOutputVolume);
				UART_Printf("\nHeadphone Volume Level : 0x%x", WM9713_GetVolume(AUDIO_Tx));		
				return TRUE;
			}
			else
			{
				UART_Printf("\nLimit Volume Range!");
				if( ( uUpDownVolume == 'u') || (uUpDownVolume == 'U') )
					(pInfor->m_uOutputVolume)++;
				else if ( ( uUpDownVolume == 'd') || (uUpDownVolume == 'D') ) 
					(pInfor->m_uOutputVolume)--;
				return FALSE;
			}
			break;
		case STAC9767:				
		default:
			if ((s16) pInfor->m_uOutputVolume <= 0x0000) 
			{
				UART_Printf("\nLimit Volume Range!");
				if( ( uUpDownVolume == 'u') || (uUpDownVolume == 'U') )
					(pInfor->m_uOutputVolume) += 0x0101;
				else if ( ( uUpDownVolume == 'd') || (uUpDownVolume == 'D') ) 
					(pInfor->m_uOutputVolume) -= 0x0101;
				return FALSE;
			} 
			else 
			{
				pInfor->m_uOutputVolume -= 0x0101;
				AC97_CodecCmd(WRITE,0x04, pInfor->m_uOutputVolume);		// PCM out Volume Up
				UART_Printf("\nSet Level (In AC97 Codec 04h Reg.): 0x%x", pInfor->m_uOutputVolume);
				UART_Printf("\nHeadphone Volume Level (In AC97 Codec 04h Reg.): 0x%x", AC97_CodecCmd(READ, 0x04,0));
				return true;
			}
			break;
	}		
}

u8 AC97_InitCodec(AC97_CHANNEL eCh)
{
	AC97_Infor* pInfor = AC97_GetInfor();	
	switch(pInfor->m_uCodecID)
	{
		case WM9713:
			if (eCh == PCM_IN)
				WM9713_CodecInit(AUDIO_Rx, ACLinkSlot34, pInfor->m_uSamplingRate, Master, Word16, pInfor->m_eADCSource, CodecPort_1st);			// Codec Initialize
			else if (eCh == MIC_IN)
				WM9713_CodecInit(AUDIO_Rx, ACLinkSlot6, pInfor->m_uSamplingRate, Master, Word16, pInfor->m_eADCSource, CodecPort_1st);			// Codec Initialize
			else if (eCh == PCM_OUT)
				WM9713_CodecInit(AUDIO_Tx, ACLinkSlot34, pInfor->m_uSamplingRate, Master, Word16, pInfor->m_eADCSource, CodecPort_1st);			// Codec Initialize
			else if (eCh == PCM_InOut)
				WM9713_CodecInit(AUDIO_TxRx, ACLinkSlot34, pInfor->m_uSamplingRate, Master, Word16, pInfor->m_eADCSource, CodecPort_1st);			// Codec Initialize
			else if (eCh == MIC_InOut)
				WM9713_CodecInit(AUDIO_TxRx, ACLinkSlot6, pInfor->m_uSamplingRate, Master, Word16, pInfor->m_eADCSource, CodecPort_1st);			// Codec Initialize
			break;
		case STAC9767:
		default:
			break;
	}
	return TRUE;
}

void AC97_ExitCodec(AC97_CHANNEL eCh)
{
	AC97_Infor* pInfor = AC97_GetInfor();	
	switch(pInfor->m_uCodecID)
	{
		case WM9713:
			switch(eCh)
			{
				case PCM_OUT:
					break;
				case PCM_IN:
					break;
				case MIC_IN:
					break;
			}
			break;
		case STAC9767:
		default:
			break;
	}
}

void AC97_ExitCodecPCMOut(void)
{
	//DACs off
	UART_Printf("\n\n=>DACs off PR1\n");
	AC97_CodecCmd((AC97_CMD)0,0x26,(1<<8)|(1<<9));
	AC97_ControllerState();
	UART_Printf("AC97 Codec Powerdown Ctrl/Stat 0x26 Reg.: 0x%x\n", AC97_CodecCmd(READ,0x26,0x0000));	

	//Analog off
	UART_Printf("\n=>Analog off PR2\n");
	AC97_CodecCmd((AC97_CMD)0,0x26,(1<<8)|(1<<9)|(1<<10));
	AC97_ControllerState();
	UART_Printf("AC97 Codec Powerdown Ctrl/Stat 0x26 Reg.: 0x%x\n", AC97_CodecCmd(READ,0x26,0x0000));	

	//Digital I/F off
	UART_Printf("\n=>Digital I/F off PR4\n");
	AC97_CodecCmd((AC97_CMD)0,0x26,(1<<8)|(1<<9)|(1<<10)|(1<<12));
	AC97_ControllerState();
	UART_Printf("AC97 Codec Powerdown Ctrl/Stat 0x26 Reg.: 0x%x\n", AC97_CodecCmd(READ,0x26,0x0000));	
}

void AC97_ExitCodecPCMIn(u16 uDACsOff)
{
	//ADCs off
	UART_Printf("\n\n=>ADCs off PR0\n");
	AC97_CodecCmd(WRITE,0x26,(1<<8));
	AC97_ControllerState();
	UART_Printf("AC97 Codec Powerdown Ctrl/Stat 0x26 Reg.: 0x%x\n", AC97_CodecCmd(READ,0x26,0x0000));

	if(uDACsOff == 1)
	{
		//DACs off
		UART_Printf("\n\n=>DACs off PR1\n");
		AC97_CodecCmd(WRITE,0x26,(1<<8)|(1<<9));
		AC97_ControllerState();
		UART_Printf("AC97 Codec Powerdown Ctrl/Stat 0x26 Reg.: 0x%x\n", AC97_CodecCmd(READ,0x26,0x0000));
	}
	//Analog off
	UART_Printf("\n=>Analog off PR2\n");
	AC97_CodecCmd(WRITE,0x26,(1<<8)|(1<<9)|(1<<10));
	AC97_ControllerState();
	UART_Printf("AC97 Codec Powerdown Ctrl/Stat 0x26 Reg.: 0x%x\n", AC97_CodecCmd(READ,0x26,0x0000));	

	//Digital I/F off
	UART_Printf("\n=>Digital I/F off PR4\n");
	AC97_CodecCmd(WRITE,0x26,(1<<8)|(1<<9)|(1<<10)|(1<<12));
	AC97_ControllerState();
	UART_Printf("AC97 Codec Powerdown Ctrl/Stat 0x26 Reg.: 0x%x\n", AC97_CodecCmd(READ,0x26,0x0000));
}


void AC97_ExitCodecMICIn(u16 uDACsOff)
{
	//ADCs off
	UART_Printf("\n\n=>ADCs off PR0\n");
	AC97_CodecCmd(WRITE,0x26,(1<<8));
	AC97_ControllerState();
	UART_Printf("AC97 Codec Powerdown Ctrl/Stat 0x26 Reg.: 0x%x\n", AC97_CodecCmd(READ,0x26,0x0000));

	if(uDACsOff == 1)
	{
		//DACs off
		UART_Printf("\n\n=>DACs off PR1\n");
		AC97_CodecCmd(WRITE, 0x26,(1<<8)|(1<<9));
		AC97_ControllerState();
		UART_Printf("AC97 Codec Powerdown Ctrl/Stat 0x26 Reg.: 0x%x\n", AC97_CodecCmd(READ,0x26,0x0000));
	}
	
	//Analog off
	UART_Printf("\n=>Analog off PR2\n");
	AC97_CodecCmd(WRITE, 0x26,(1<<8)|(1<<9)|(1<<10));
	AC97_ControllerState();
	UART_Printf("AC97 Codec Powerdown Ctrl/Stat 0x26 Reg.: 0x%x\n", AC97_CodecCmd(READ,0x26,0x0000));	

	//Digital I/F off
	UART_Printf("\n=>Digital I/F off PR4\n");
	AC97_CodecCmd(WRITE, 0x26,(1<<8)|(1<<9)|(1<<10)|(1<<12));
	AC97_ControllerState();
	UART_Printf("AC97 Codec Powerdown Ctrl/Stat 0x26 Reg.: 0x%x\n", AC97_CodecCmd(READ,0x26,0x0000));	
}

//////////
// Function Name : AC97_CodecInitPD
// Function Description : ?
//   
// Input : 	None
// Output : None
// Version : v0.1
void AC97_CodecInitPD(void)
{
	if (AC97_GetInfor()->m_uCodecID == STAC9767)	
	{
		UART_Printf("\nSoft Reset\n");
		AC97_CodecCmd(WRITE,0x00,0x683F);		//Codec Soft Reset : 16bit In/Out 	
		UART_Printf("AC97 Codec 0x26 Reg.: 0x%x\n\n", AC97_CodecCmd(READ,0x26,0x0000));
	}
}
